package com.wonders.ghy.juc.cas;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.atomic.AtomicStampedReference;

/**
 * ABA问题的解决 AtomicStampedReference
 **/
public class ABADemo {
    static AtomicReference<Integer> atomicReference = new AtomicReference<>(100);
    static AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<>(100,1);
    public static void main(String[] args) {
        System.out.println("以下是ABA问题的产生-----------------");
        new Thread(()->{
            // 暂停了1秒钟t1 保证在t2线程在没开始改变数据的时候 t2已经拿到了数据
            try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) { e.printStackTrace(); }
            atomicReference.compareAndSet(100,101);
            atomicReference.compareAndSet(101,100);
            },"t1").start();
        new Thread(()->{
            // 暂停了3秒钟 保证上面的t1线程完成了一次ABA操作
            try {TimeUnit.SECONDS.sleep(3);} catch (InterruptedException e) { e.printStackTrace(); }
            System.out.println(atomicReference.compareAndSet(100, 1024)+"\t"+atomicReference.get());
        },"t2").start();

        // 暂停一会线程 准备开始ABA问题的解决
        try {TimeUnit.SECONDS.sleep(5);} catch (InterruptedException e) { e.printStackTrace(); }
        System.out.println("以下是ABA问题的解决-----------------");
        new Thread(()->{
            // 得到时间戳版本号
            int stamp = atomicStampedReference.getStamp();
            System.out.println(Thread.currentThread().getName()+"\t第1次版本号:"+stamp);
            // 暂停了1秒钟t3 保证在t3线程在没开始改变数据的时候 t4已经拿到了数据
            try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) { e.printStackTrace(); }
            atomicStampedReference.compareAndSet(100,101,atomicStampedReference.getStamp(),atomicStampedReference.getStamp()+1);
            System.out.println(Thread.currentThread().getName()+"\t第2次版本号:"+atomicStampedReference.getStamp());
            atomicStampedReference.compareAndSet(101,100,atomicStampedReference.getStamp(),atomicStampedReference.getStamp()+1);
            System.out.println(Thread.currentThread().getName()+"\t第3次版本号:"+atomicStampedReference.getStamp());
        },"t3").start();
        new Thread(()->{
            // 得到时间戳版本号
            int stamp = atomicStampedReference.getStamp();
            // 暂停了3秒钟t4 保证上面的t3线程完成了一次ABA操作
            try {TimeUnit.SECONDS.sleep(3);} catch (InterruptedException e) { e.printStackTrace(); }
            boolean result = atomicStampedReference.compareAndSet(100,2019,stamp,stamp+1);
            atomicStampedReference.getStamp();
            System.out.println(Thread.currentThread().getName()+"\t修改成功否"+result+"\t当前版本号为"+atomicStampedReference.getStamp());
            System.out.println(Thread.currentThread().getName()+"\t当前实际最新值:"+atomicStampedReference.getReference());
        },"t4").start();
    }
}
